package cn.icare.cms.impl;

import cn.icare.cms.*;
import cn.icare.cms.dao.mapper.CustomMapper;
import cn.icare.cms.dao.mapper.OrderAddressMapper;
import cn.icare.cms.dao.mapper.OrderItemMapper;
import cn.icare.cms.dao.mapper.OrderMapper;
import cn.icare.cms.dao.po.Order;
import cn.icare.cms.dao.po.OrderAddress;
import cn.icare.cms.dao.po.OrderItem;
import cn.icare.cms.model.enums.OrderStatusEnum;
import cn.icare.cms.model.enums.PayTypeEnum;
import cn.icare.cms.model.ro.*;
import cn.icare.cms.model.vo.rest.MsgDatasVO;
import cn.icare.cms.model.vo.rest.OrderAddressVo;
import cn.icare.cms.model.vo.rest.OrderItemVo;
import cn.icare.cms.model.vo.rest.OrderVo;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderAddressMapper orderAddressMapper;

    @Resource
    private OrderItemMapper orderItemMapper;


    @Resource
    private CustomMapper customMapper;

    private final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);


    @Override
    public long createOne(AddOrderRo ro) {

        Long orderId = 0L;
        //1.保存订单主表
        Order order = new Order();
        order.setCode(OrderCodeUtil.getOrderCode(ro.getMemberid()));
        order.setAmmount(ro.getAmmount());
        order.setMemberid(ro.getMemberid());
        order.setMembername(ro.getMembername());
        order.setStatus(OrderStatusEnum.WAIT_PAY.getCode()); //创建订单时状态为待付款
        order.setCreatetime(new Date());
        order.setCouponid(ro.getCouponid()); //优惠券id
        order.setDisamount(ro.getDisamount()); //优惠金额
        order.setSumamount(ro.getSumamount()); //订单原价
        order.setExpressfee(ro.getExpressfee()); //配送费
        order.setMemo(ro.getMemo()); //备注信息
        order.setExpresstime(ro.getExpresstime());//配送时间

        int result = this.orderMapper.insertSelective(order);
        if (result > 0) {
            orderId = order.getId();

        } else {
            this.logger.error("createOne 异常，数据写入t_order表失败");
        }
        return orderId;
    }

    @Override
    public boolean updateStatus(Long id, Integer status) {
        return this.updateStatus(id, status, 0L);
    }


    @Override
    public boolean updatePayFinished(Long id, PayTypeEnum payTypeEnum) {

        try {
            Order order = new Order();
            order.setId(id);
            order.setStatus(OrderStatusEnum.WAIT_SEND.getCode());//更新为待发货
            order.setPaytype(payTypeEnum.getCode());//付款方式
            order.setPaytime(new Date()); //付款时间
            int result = this.orderMapper.updateByPrimaryKeySelective(order);
            return result > 0;
        } catch (Exception ex) {
            this.logger.error(String.format("updatePayFinished 异常，id:%d,payTypeEnum:%d,错误信息:%s", id
                    , payTypeEnum.getName(), ex.getMessage()));
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean updateArrivalFinished(Long id, Long arrivalMemberId) {
        return this.updateStatus(id, OrderStatusEnum.WAIT_COMMENT.getCode(), arrivalMemberId);
    }

    @Override
    public boolean deleteOne(Long id) {

        try {
            //删除订单主表
            this.orderMapper.deleteByPrimaryKey(id);
            //删除订单收货信息表
            Example example = new Example(OrderAddress.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("orderid", id);
            this.orderAddressMapper.deleteByExample(example);

            //删除订单商品列表
            Example exampleItem = new Example(OrderItem.class);
            Example.Criteria criteriaitem = exampleItem.createCriteria();
            criteriaitem.andEqualTo("orderid", id);
            this.orderItemMapper.deleteByExample(exampleItem);
            return true;
        } catch (Exception ex) {
            this.logger.error("deleteOne 异常", ex);
            return false;
        }

    }

    @Override
    public boolean deleteBatch(List<Long> ids) {

        boolean result = false;
        try {
            if (ListUtil.isNotEmpty(ids)) {
                //删除订单主表
                Example example = new Example(Order.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andIn("id", ids);
                this.orderMapper.deleteByExample(example);

                //删除订单收货信息表
                Example exampleAddress = new Example(OrderAddress.class);
                Example.Criteria criteriaAddress = exampleAddress.createCriteria();
                criteriaAddress.andIn("orderid", ids);
                this.orderAddressMapper.deleteByExample(criteriaAddress);

                //删除订单商品列表
                Example exampleItem = new Example(OrderItem.class);
                Example.Criteria criteriaItem = exampleItem.createCriteria();
                criteriaItem.andIn("orderid", ids);
                this.orderItemMapper.deleteByExample(criteriaItem);
                result = true;
            }
        } catch (Exception e) {
            this.logger.error("deleteBatch 异常", e);

        }
        return result;
    }

    @Override
    public Order getOne(Long id) {

        return this.orderMapper.selectByPrimaryKey(id);

    }


    @Override
    public MsgDatasVO getList(SearchOrderListRo ro) {

        MsgDatasVO result = new MsgDatasVO();
        try {
            List<Order> dataList = new ArrayList<>();
            if (ro.getPageSize() > 0) {
                PageHelper.startPage(ro.getPageNum(), ro.getPageSize());
                dataList = this.orderMapper.selectListByCustom(ro);
                PageInfo pageInfo = new PageInfo(dataList);
                result.setTotal(pageInfo.getTotal());

            } else {
                dataList = this.orderMapper.selectListByCustom(ro);
                result.setTotal(dataList.size());
            }
            result.setDatas(dataList);
        } catch (Exception e) {
            this.logger.error("getList 异常", e);
        }
        return result;
    }

    @Override
    public OrderVo getDetail(Long id) {

        OrderVo orderVo = null;
        //1-获取订单信息
        Order order = this.orderMapper.selectByPrimaryKey(id);
        if (order != null) {
            orderVo = new OrderVo();
            orderVo.setId(order.getId());
            orderVo.setAmmount(order.getAmmount());
            orderVo.setCode(order.getCode());
            orderVo.setCreatetime(order.getCreatetime());
            orderVo.setDisamount(order.getDisamount());
            orderVo.setExpressfee(order.getExpressfee());
            orderVo.setExpresstime(order.getExpresstime());
            orderVo.setMemo(order.getMemo());
            orderVo.setStatus(order.getStatus());
            orderVo.setSumamount(order.getSumamount());
            orderVo.setPaytype(order.getPaytype());
            orderVo.setPaytime(order.getPaytime());
            orderVo.setArrivaltime(order.getArrivaltime());
            //2-获取订单商品
            List<OrderItem> orderItems = getOrderItems(id, "num", "title", "price", "total", "picurl");
            if (orderItems != null && orderItems.size() > 0) {
                List<OrderItemVo> orderItemVos = orderItems.stream().map
                        (a -> {
                            //在此转把A转换为B
                            return new OrderItemVo(
                                    a.getNum()
                                    , a.getTitle()
                                    , a.getPrice()
                                    , a.getTotal()
                                    , a.getPicurl()
                            );
                        }).collect(Collectors.toList());
                orderVo.setItems(orderItemVos);
            }

            //3-获取订单收货信息
            Example exampleAddress = new Example(OrderAddress.class);
            Example.Criteria criteriaAddress = exampleAddress.createCriteria();
            criteriaAddress.andEqualTo("orderid", id);
            exampleAddress.selectProperties("name", "mobile", "address");
            OrderAddress orderAddress = this.orderAddressMapper.selectOneByExample(exampleAddress);

            if (orderAddress != null) {
                OrderAddressVo orderAddressVo = new OrderAddressVo();
                orderAddressVo.setName(orderAddress.getName());
                orderAddressVo.setAddress(orderAddress.getAddress());
                orderAddressVo.setMobile(orderAddress.getMobile());
                orderVo.setOrderAddress(orderAddressVo);
            }

        }

        return orderVo;
    }

    @Override
    public List<OrderItem> getOrderItems(Long id) {
        return getOrderItems(id, "itemid", "storedid", "type", "num");
    }

    @Override
    public Order getOneByCode(String code) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("code", code);
        return this.orderMapper.selectOneByExample(example);
    }

    @Override
    public List<Order> getNeedCancelList() {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("status", OrderStatusEnum.WAIT_PAY.getCode());
        criteria.andLessThan("createtime", DateUtil.addMiniter(new Date(), -30));
        example.selectProperties("id");
        return this.orderMapper.selectByExample(example);
    }

    @Override
    public boolean updateSendStart(Long id, Long arrivalMemberId) {


        return this.updateStatus(id, OrderStatusEnum.SENDING.getCode(), arrivalMemberId);
    }

    @Override
    public List<Integer> statisticOrderList(Integer status) {
        List<Integer> nums = new ArrayList<>();
        Date endTime = new Date();
        int weeknum = DateUtil.getWeekday();
        Date startTime = DateUtil.addDay(endTime, -(weeknum - 1));
        String sql = String.format("select  DAYOFWEEK(createtime) time,count(1) num from t_order where createtime>='%s' and createtime<='%s'",
                DateUtil.formateToDateTime(startTime, "yyyy-MM-dd 00:00:00"),
                DateUtil.formateToDateTime(endTime, "yyyy-MM-dd 23:59:59")
        );
        if (status > -1) {
            sql += " and status=" + status;
        }

        sql += " GROUP BY DAYOFWEEK(createtime) ORDER BY createtime ASC";
        List<Map<String, Object>> dataList = customMapper.select(sql);
        for (int i = 1; i <= 7; i++) {
            if (i == 7) {
                nums.add(getNum(dataList, 1));
            } else {
                nums.add(getNum(dataList, i + 1));
            }
        }
        return nums;
    }

    @Override
    public List<Map<String, Object>> getExportItemList(String beginTime, String endTime, String areaCode) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("select  a.title,SUM(a.num) num,a.type from t_order_item a ,t_order b,t_order_address c where a.orderid=b.id ");
        stringBuffer.append(" and c.orderid=b.id ");
        stringBuffer.append(" and b.`status`=1");
        if (StringUtil.isNotEmpty(beginTime)) {
            stringBuffer.append(String.format(" and b.createtime>='%s'", beginTime));

        }
        if (StringUtil.isNotEmpty(endTime)) {
            stringBuffer.append(String.format(" and b.createtime<='%s'", endTime));
        }
        if (StringUtil.isNotEmpty(areaCode)) {
            stringBuffer.append(String.format(" and c.district='%s'", areaCode));
        }
        stringBuffer.append(" GROUP BY a.itemid,a.title,a.type");
        return this.customMapper.select(stringBuffer.toString());
    }

    @Override
    public boolean batchUpdateSend(Long arrivalMemberId) {
        Example example = new Example(Order.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("status", OrderStatusEnum.WAIT_SEND.getCode());
        Order order = new Order();
        order.setStatus(OrderStatusEnum.SENDING.getCode());
        order.setArrivalmemberid(arrivalMemberId);
        order.setUpdatetime(new Date());
        int result = this.orderMapper.updateByExampleSelective(order, example);
        return result > 0;
    }

    @Override
    public MsgDatasVO getSysList(SearchOrderListRo ro) {
        MsgDatasVO result = new MsgDatasVO();
        try {
            List<cn.icare.cms.dao.custompo.OrderVo> dataList = new ArrayList<>();
            if (ro.getPageSize() > 0) {
                PageHelper.startPage(ro.getPageNum(), ro.getPageSize());
                dataList = this.orderMapper.selectSystemListByCustom(ro);
                PageInfo pageInfo = new PageInfo(dataList);
                result.setTotal(pageInfo.getTotal());

            } else {
                dataList = this.orderMapper.selectSystemListByCustom(ro);
                result.setTotal(dataList.size());
            }
            result.setDatas(dataList);
        } catch (Exception e) {
            this.logger.error("getList 异常", e);
        }
        return result;
    }

    @Override
    public boolean updateSysMemo(UpdateOrderSysMemoRo ro) {
        try {
            Order order = new Order();
            order.setId(ro.getOrderId());
            order.setSysmemo(ro.getSysMemo());
            int result = this.orderMapper.updateByPrimaryKeySelective(order);
            return result > 0;
        } catch (Exception ex) {
            this.logger.error(String.format("updateSysMemo 异常，参数:%s", JSON.toJSONString(ro), ex.getMessage()));
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public List<Map<String, Object>> getFinishedList(String beginTime, String endTime, String areaCode) {
        StringBuilder sb = new StringBuilder();
        sb.append("select b.name,b.mobile,b.address,a.ammount,a.createtime");
        sb.append(" from t_order a,t_order_address b where a.id=b.orderid");
        sb.append(" and a.status in(2,3,5)"); //订单状态为配送中、待评价或已经完成三类
        if (StringUtil.isNotEmpty(beginTime)) {
            sb.append(String.format(" and a.createtime>='%s'", beginTime));
        }
        if (StringUtil.isNotEmpty(endTime)) {
            sb.append(String.format(" and a.createtime<='%s'", endTime));
        }
        if (StringUtil.isNotEmpty(areaCode)) {
            sb.append(String.format(" and b.district='%s'", areaCode));
        }
        sb.append(" order by a.createtime desc");


        return this.customMapper.select(sb.toString());
    }

    @Override
    public Map<String, Object> getMasterOrderList(Long masterId, String beginTime, String endTime, Integer pageNum, Integer pageSize) {
        Map<String, Object> map = new HashMap<>();
        Long total = 0L;
        BigDecimal ammount = new BigDecimal("0");
        String where = "a.id=b.orderid ";
        where += " and b.masterid=" + masterId;
        where += " and a.`status` in(1,2,3,5)";

        if (StringUtil.isNotEmpty(beginTime)) {
            where += String.format(" and a.createtime>='%s'", beginTime);
        }
        if (StringUtil.isNotEmpty(endTime)) {
            where += String.format(" and a.createtime<='%s'", endTime);
        }


        StringBuffer sb = new StringBuffer();
        sb.append("select b.`name`,a.ammount,a.createtime,a.id from t_order a,t_order_address b where ");
        sb.append(where);
        sb.append(" ORDER BY a.createtime DESC");


        PageHelper.startPage(pageNum, pageSize);
        List<Map<String, Object>> dataList = customMapper.select(sb.toString());
        PageInfo pageInfo = new PageInfo(dataList);
        total = pageInfo.getTotal();

        StringBuffer sbSumAmmount = new StringBuffer();
        sbSumAmmount.append("select IFNULL(SUM(a.ammount),0) ammount from t_order a,t_order_address b where ");
        sbSumAmmount.append(where);
        List<Map<String, Object>> listSum = customMapper.select(sbSumAmmount.toString());
        if (listSum != null && listSum.size() > 0) {
            ammount = new BigDecimal(listSum.get(0).get("ammount") + "");
        }
        map.put("total", total);
        map.put("ammount", ammount);
        map.put("datas", dataList);
        return map;
    }

    @Override
    public Map<String, Object> getMasterOrderTotal(Long masterId, String beginTime, String endTime) {
        Map<String, Object> map = new HashMap<>();
        Long total = 0L;
        BigDecimal ammount = new BigDecimal("0");
        BigDecimal allammount = new BigDecimal("0");
        String where = "a.id=b.orderid ";
        where += " and b.masterid=" + masterId;
        where += " and a.`status` in(1,2,3,5)";

        if (StringUtil.isNotEmpty(beginTime)) {
            where += String.format(" and a.createtime>='%s'", beginTime);
        }
        if (StringUtil.isNotEmpty(endTime)) {
            where += String.format(" and a.createtime<='%s'", endTime);
        }


        StringBuffer sbSumAmmount = new StringBuffer();
        sbSumAmmount.append("select IFNULL(SUM(a.ammount),0) ammount,count(1) total from t_order a,t_order_address b where ");
        sbSumAmmount.append(where);
        List<Map<String, Object>> listSum = customMapper.select(sbSumAmmount.toString());
        if (listSum != null && listSum.size() > 0) {
            ammount = new BigDecimal(listSum.get(0).get("ammount") + "");
            total = Long.valueOf(listSum.get(0).get("total") + "");
        }

        StringBuffer sbAllSum = new StringBuffer();
        sbAllSum.append("select IFNULL(SUM(a.ammount),0) ammount from t_order a,t_order_address b where");

        sbAllSum.append(" a.id=b.orderid ");
        sbAllSum.append(" and b.masterid=" + masterId);
        sbAllSum.append(" and a.`status` in(1,2,3,5)");
        List<Map<String, Object>> listAllSum = customMapper.select(sbAllSum.toString());
        if (listAllSum != null && listAllSum.size() > 0) {
            allammount = new BigDecimal(listAllSum.get(0).get("ammount") + "");
        }

        map.put("total", total);
        map.put("ammount", ammount);
        map.put("allammount", allammount);
        return map;
    }


    //#region private
    private boolean updateStatus(Long id, Integer status, Long arrivalMemberId) {
        try {
            Order order = new Order();
            order.setId(id);
            order.setStatus(status);
            if (OrderStatusEnum.WAIT_COMMENT.getCode() == status) {
                //配送完成，等待客户收货确认的状态
                Date currentDate = new Date();
                order.setArrivaltime(currentDate);
                order.setUpdatetime(currentDate);
                order.setArrivalmemberid(arrivalMemberId);
            } else if (OrderStatusEnum.SENDING.getCode() == status) {
                //配送中，更新updatetime时间和status状态
                Date currentDate = new Date();
                order.setUpdatetime(currentDate);
                order.setArrivalmemberid(arrivalMemberId);
            } else {
                order.setUpdatetime(new Date());
            }
            int result = this.orderMapper.updateByPrimaryKeySelective(order);
            return result > 0;
        } catch (Exception ex) {
            this.logger.error(String.format("updateStatus 异常，id:%d,status:%d,错误信息:%s", id
                    , status, ex.getMessage()));
            ex.printStackTrace();
            return false;
        }

    }


    private List<OrderItem> getOrderItems(Long id, String... columns) {

        Example example = new Example(OrderItem.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderid", id);
        example.selectProperties(columns);
        List<OrderItem> orderItems = this.orderItemMapper.selectByExample(example);
        return orderItems;
    }

    private Integer getNum(List<Map<String, Object>> list, Integer weekNum) {
        Integer result = 0;
        if (list != null && list.size() > 0) {
            Optional<Map<String, Object>> mapOptional = list.stream().filter(item ->
                    item.get("time").toString().equals(weekNum.toString())
            ).findFirst();
            if (mapOptional != null && mapOptional.isPresent()) {
                Map map = mapOptional.get();
                if (map != null) {
                    result = Integer.valueOf(map.get("num").toString());
                }
            }

        }
        return result;
    }
    //#endregion


}
